""" redis操作方法包
@Project: Rebar
@File: mapper.py
@Author: hzc
@Date: 2023/3/22 13:29
"""
import traceback

from fastapi import Header
from starlette.requests import Request
from config import ACCESS_TOKEN_EXPIRE_MINUTES, ACCESS_TOKEN_REFRESH, SUPER_TOKEN, EMAIL_TOKEN, USER_TOKEN
# from model.db import TbUser
# from model.db.mapper.log_mapper import add_log
# from utils import create_token, ErrorCode, error_res, success_res, SuccessCode, obj_to_dict, AllException
from util import success_res, obj_to_dict, SuccessCode, create_token, error_res, ErrorCode


async def refresh_token(request: Request, user_id, token, token_type):
    """
    校验redis的token并更新token的过期时间
    redis.ttl(key) -> return: -1表示没有过期时间，-2表示键不存在，>0代表当前的剩余时间
    :param request:
    :param token:
    :param payload:
    :param callback: 回调方法
    :return:
    """
    try:
        current_redis = request.app.state.redis
        token_key = token_type.format(user_id)
        # 获取token的过期时间
        ttl = await current_redis.ttl(token_key)
        # 若token剩余时间小于定义的token刷新时间，则重新生成token，并保存到redis中
        await current_redis.setex(name=token_key, time=ACCESS_TOKEN_EXPIRE_MINUTES * 60, value=token)

    except Exception as e:
        print(e.__traceback__.tb_lineno, "redis/utils.py")
        print(e)
        return error_res(ErrorCode.SERVER)


# async def redis_user_has_login(request: Request, user_id):


async def redis_verify_and_refresh_token(request: Request, payload, token, callback, token_type):
    """
    校验redis的token并更新token的过期时间
    redis.ttl(key) -> return: -1表示没有过期时间，-2表示键不存在，>0代表当前的剩余时间
    :param request:
    :param token:
    :param payload:
    :param callback: 回调方法
    :return:
    """
    try:
        current_redis = request.app.state.redis
        token_key = token_type.format(payload.get("user_id"))
        # 获取redis中的token并进行判断，redis获取的是bytes类型
        redis_token = (await current_redis.get(token_key))
        if not redis_token:  # token过期
            return error_res(ErrorCode.EXPIRED_TOKEN)
        redis_token = redis_token.decode()
        if redis_token != token:  # token不正确
            return error_res(ErrorCode.INVALID_TOKEN)
        # 获取token的过期时间
        ttl = await current_redis.ttl(token_key)
        # 若token剩余时间小于定义的token刷新时间，则延长过期时间，并保存到redis中
        if 0 < ttl < ACCESS_TOKEN_REFRESH * 60:
            # 延长token过期时间
            await current_redis.setex(name=token_key, time=ACCESS_TOKEN_EXPIRE_MINUTES * 60, value=redis_token)
        response = await callback(request)
        response.headers['token'] = token  # 将新生成的token放入响应头返回
        return response
    except Exception as e:
        print(e.__traceback__.tb_lineno, "redis/utils.py")
        print(e)
        return error_res(ErrorCode.SERVER)


async def redis_save_token(request: Request, user_id, token, token_type):
    """
    将token保存到redis中
    :param request:
    :param user_id:
    :param token:
    :return:
    """
    token_key = token_type.format(user_id)
    await request.app.state.redis.setex(name=token_key, time=ACCESS_TOKEN_EXPIRE_MINUTES * 60, value=token)


async def redis_user_has_login_num(request: Request):
    """
    判断用户是否登录
    :param request: Request请求
    :param user_id: 用户ID
    :return:
    """
    # REDIS_TOKEN: redis_token-{}
    # token_key = REDIS_TOKEN.format(user_id)
    # 使用SCAN命令遍历所有的键
    keys = []
    cursor = '0'
    while cursor != 0:
        cursor, scan_keys = await request.app.state.redis.scan(cursor=cursor)
        keys.extend(scan_keys)
    filterKeys = [token for token in keys if token.decode('utf-8').find('token') != -1]

    return len(filterKeys)


async def redis_save_emailcode(request: Request, email: str, emailcode: str):
    try:
        current_redis = request.app.state.redis
        token_key = EMAIL_TOKEN.format(email)
        # current_redis.setex()
        # token = create_token({user_name: emailcode})
        await current_redis.setex(name=token_key, time=ACCESS_TOKEN_EXPIRE_MINUTES * 5, value=emailcode)
        redis_token = await current_redis.get(token_key)  # 校验用户是否登录
        return redis_token
    except Exception as e:
        print(e, e.__traceback__.tb_lineno)


async def redis_verify_email(request: Request, email, email_code):
    try:
        current_redis = request.app.state.redis
        token_key = email

        token_key = EMAIL_TOKEN.format(token_key)
        redis_email_code = await current_redis.get(token_key)  # 获取redis中的token并进行判断，redis获取的是bytes类型
        if redis_email_code:  # 判断redis是否存在 email_key
            redis_token = redis_email_code.decode()
            print(redis_token)
            print(email_code)
            if redis_token != email_code:  # 验证码不正确

                return ErrorCode.EMAIL_CODE_ERROR
            return SuccessCode.EMAILCODE_OK

        else:

            return ErrorCode.EMAIL_CODE_ISNONE


    except Exception as e:  # 捕获相应处理异常
        print(e, e.__traceback__.tb_lineno, "redis/utils.py")


async def redis_delete_token(request: Request, user_id):
    """
    删除redis中指定token
    :param request:
    :param user_id:
    :return:
    """
    try:
        token_key = USER_TOKEN.format(user_id)
        # 无需判断用户是否已登录，这些在token校验中间件中已经判断过了
        await request.app.state.redis.delete(token_key)
    except Exception as e:
        print("redis/utils.py", e, e.__traceback__.tb_lineno)
